package com.javabi.htmlbuilder.css;

import java.util.Collection;

import com.javabi.htmlbuilder.DocumentBuilder;
import com.javabi.htmlbuilder.css.unit.CSSUnit;

/**
 * An CSS Builder.
 */
public class CSSBuilder extends DocumentBuilder<CSSBuilder> {

	/**
	 * Creates a new CSS builder.
	 */
	public CSSBuilder() {
	}

	/**
	 * Append the given property to this builder.
	 * @param propertyName the property name.
	 * @param value the value.
	 * @return this builder.
	 */
	public CSSBuilder property(CSSPropertyName propertyName, String value) {
		document.append(propertyName.getName());
		document.append(':').append(' ');
		document.append(value);
		return this;
	}

	/**
	 * Append the given property to this builder.
	 * @param propertyName the property name.
	 * @return this builder.
	 */
	public CSSBuilder property(CSSPropertyName propertyName) {
		document.append(propertyName.getName());
		document.append(':').append(' ');
		return this;
	}

	/**
	 * Append a semi-colon.
	 * @return this builder.
	 */
	public CSSBuilder semi() {
		document.append(';');
		return this;
	}

	/**
	 * Append a percentage.
	 * @param percent the percentage.
	 * @return this builder.
	 */
	public CSSBuilder percent(Number percent) {
		document.append(percent);
		document.append('%');
		return this;
	}

	/**
	 * Append a pixels.
	 * @param pixels the number of pixels.
	 * @return this builder.
	 */
	public CSSBuilder px(Number pixels) {
		document.append(pixels);
		document.append('p').append('x');
		return this;
	}

	/**
	 * Append a pixels.
	 * @param pixels the number of pixels.
	 * @return this builder.
	 */
	public CSSBuilder pixels(Number pixels) {
		return px(pixels);
	}

	/**
	 * Append a points.
	 * @param points the number of points.
	 * @return this builder.
	 */
	public CSSBuilder pt(Number points) {
		document.append(points);
		document.append('p').append('t');
		return this;
	}

	/**
	 * Append a points.
	 * @param points the number of points.
	 * @return this builder.
	 */
	public CSSBuilder points(Number points) {
		return pt(points);
	}

	/**
	 * Append a picas.
	 * @param picas the number of picas.
	 * @return this builder.
	 */
	public CSSBuilder pc(Number picas) {
		document.append(picas);
		document.append('p').append('c');
		return this;
	}

	/**
	 * Append a picas.
	 * @param picas the number of picas.
	 * @return this builder.
	 */
	public CSSBuilder picas(Number picas) {
		return pc(picas);
	}

	/**
	 * Append an em.
	 * @param em the number of em.
	 * @return this builder.
	 */
	public CSSBuilder em(Number em) {
		document.append(em);
		document.append('e').append('m');
		return this;
	}

	/**
	 * Append an ex.
	 * @param ex the number of ex.
	 * @return this builder.
	 */
	public CSSBuilder ex(Number ex) {
		document.append(ex);
		document.append('e').append('x');
		return this;
	}

	/**
	 * Append an millimeters.
	 * @param millimeters the number of millimeters.
	 * @return this builder.
	 */
	public CSSBuilder mm(Number millimeters) {
		document.append(millimeters);
		document.append('m').append('m');
		return this;
	}

	/**
	 * Append an millimeters.
	 * @param millimeters the number of millimeters.
	 * @return this builder.
	 */
	public CSSBuilder millimeters(Number millimeters) {
		return mm(millimeters);
	}

	/**
	 * Append an centimeters.
	 * @param centimeters the number of centimeters.
	 * @return this builder.
	 */
	public CSSBuilder cm(Number centimeters) {
		document.append(centimeters);
		document.append('c').append('m');
		return this;
	}

	/**
	 * Append an centimeters.
	 * @param centimeters the number of centimeters.
	 * @return this builder.
	 */
	public CSSBuilder centimeters(Number centimeters) {
		return cm(centimeters);
	}

	/**
	 * Append a collection of names.
	 * @param names the names.
	 * @return this builder.
	 */
	public CSSBuilder names(Collection<String> names) {
		boolean comma = false;
		for (String name : names) {
			if (comma) {
				document.append(',');
			}
			comma = true;
			document.append(name);
		}
		return this;
	}

	/**
	 * Append an inches.
	 * @param inches the number of inches.
	 * @return this builder.
	 */
	public CSSBuilder in(Number inches) {
		document.append(inches);
		document.append('i').append('n');
		return this;
	}

	/**
	 * Append an inches.
	 * @param inches the number of inches.
	 * @return this builder.
	 */
	public CSSBuilder inches(Number inches) {
		return in(inches);
	}

	/**
	 * Append a number
	 * @param unit the unit.
	 * @param number the number.
	 * @return this builder.
	 */
	public CSSBuilder number(Number number, CSSUnit unit) {
		switch (unit) {
			case CENTIMETERS:
				cm(number);
				break;
			case MILLIMETERS:
				mm(number);
				break;
			case INCHES:
				in(number);
				break;
			case PIXELS:
				px(number);
				break;
			case PERCENT:
				percent(number);
				break;
			case POINTS:
				pt(number);
				break;
			case EM:
				em(number);
				break;
			case EX:
				ex(number);
				break;
			default:
				throw new IllegalArgumentException("not supported: " + unit);
		}
		return this;
	}

	/**
	 * Append CSS declarations.
	 * @param declarations the declarations.
	 * @param braces true to include braces.
	 * @return this builder.
	 */
	public CSSBuilder declarations(Collection<CSSDeclaration> declarations, boolean braces) {
		if (braces) {
			document.append(' ');
			document.append('{');
		}
		boolean comma = false;
		for (CSSDeclaration declaration : declarations) {
			if (comma) {
				document.append(';');
				document.append(' ');
			}
			comma = true;
			declaration.appendTo(this);
		}
		if (braces) {
			document.append('}');
		}
		return this;
	}

	/**
	 * Append CSS selectors.
	 * @param selectors the selectors.
	 * @return this builder.
	 */
	public CSSBuilder selectors(Collection<CSSSelector> selectors) {
		boolean comma = false;
		for (CSSSelector selector : selectors) {
			if (comma) {
				document.append(',');
			}
			comma = true;
			selector.appendTo(this);
		}
		return this;
	}

	/**
	 * Append CSS styles.
	 * @param styles the styles.
	 * @return this builder.
	 */
	public CSSBuilder styles(Collection<CSSStyle> styles) {
		boolean comma = false;
		for (CSSStyle style : styles) {
			if (comma) {
				document.append(',');
			}
			comma = true;
			style.appendTo(this);
			newLine();
		}
		return this;
	}

	/**
	 * Append text.
	 * @param text the text.
	 */
	public void append(String text) {
		document.append(text);
	}
}
